"""
Python高级特性学习 - 迭代器与生成器
=========================

本文件演示了Python中迭代器和生成器的概念、实现方式及其优势。
迭代器是实现了__iter__和__next__方法的对象，可以逐个访问元素。
生成器是一种特殊的迭代器，使用yield关键字来产生值，更加简洁高效。
"""

import sys
import time
from typing import Iterator, Generator


class CountDown:
    """自定义倒计时迭代器类
    
    这个类演示了如何创建一个自定义的迭代器。
    迭代器需要实现__iter__和__next__两个特殊方法。
    __iter__方法返回迭代器对象本身。
    __next__方法返回序列中的下一个值，在没有更多元素时抛出StopIteration异常。
    """
    
    def __init__(self, start: int):
        """初始化倒计时迭代器
        
        Args:
            start (int): 倒计时的起始值
        """
        self.start = start
    
    def __iter__(self) -> 'CountDown':
        """返回迭代器对象本身
        
        这个方法使得对象可以被用于for循环等迭代场景。
        
        Returns:
            CountDown: 返回迭代器对象本身
        """
        return self
    
    def __next__(self) -> int:
        """返回序列中的下一个值
        
        每次调用此方法都会返回当前值，并将计数器减一。
        当计数器小于0时，抛出StopIteration异常表示迭代结束。
        
        Returns:
            int: 当前的倒计时值
            
        Raises:
            StopIteration: 当倒计时结束时抛出此异常
        """
        if self.start <= 0:
            raise StopIteration
        self.start -= 1
        return self.start + 1


def fibonacci_generator(n: int) -> Generator[int, None, None]:
    """斐波那契数列生成器
    
    生成器是一种特殊的函数，使用yield关键字来产生值。
    每次调用next()或在for循环中使用时，生成器会从上次yield的位置继续执行。
    相比于返回整个列表，生成器节省内存，按需生成值。
    
    Args:
        n (int): 生成斐波那契数列的个数
        
    Yields:
        int: 斐波那契数列中的下一个数
    """
    a, b = 0, 1
    count = 0
    while count < n:
        yield a
        a, b = b, a + b
        count += 1


def infinite_counter(start: int = 0, step: int = 1) -> Generator[int, None, None]:
    """无限计数器生成器
    
    这个生成器可以无限产生数字序列，演示了生成器的惰性求值特性。
    由于是无限序列，使用时需要注意控制迭代次数。
    
    Args:
        start (int): 起始值，默认为0
        step (int): 步长，默认为1
        
    Yields:
        int: 序列中的下一个数
    """
    current = start
    while True:
        yield current
        current += step


def generator_pipeline_demo():
    """生成器管道示例
    
    演示如何将多个生成器组合成管道来处理数据。
    每个生成器负责一个处理步骤，数据在生成器之间流动。
    这种方式内存效率高，只在需要时处理数据。
    """
    print("=== 生成器管道示例 ===")
    
    def numbers() -> Generator[int, None, None]:
        """生成数字序列"""
        for i in range(10):
            yield i
    
    def square(nums: Generator[int, None, None]) -> Generator[int, None, None]:
        """计算平方"""
        for num in nums:
            yield num ** 2
    
    def even_only(nums: Generator[int, None, None]) -> Generator[int, None, None]:
        """只保留偶数"""
        for num in nums:
            if num % 2 == 0:
                yield num
    
    # 构建管道：数字 -> 平方 -> 偶数
    pipeline = even_only(square(numbers()))
    result = list(pipeline)
    print(f"管道处理结果: {result}")


def memory_efficiency_demo():
    """内存效率演示
    
    比较列表和生成器在内存使用上的差异。
    列表会一次性创建所有元素，占用大量内存。
    生成器按需生成元素，内存使用恒定。
    """
    print("\n=== 内存效率演示 ===")
    
    # 创建大列表
    large_list = [i**2 for i in range(1000000)]
    list_memory = sys.getsizeof(large_list)
    
    # 创建生成器
    large_generator = (i**2 for i in range(1000000))
    generator_memory = sys.getsizeof(large_generator)
    
    print(f"列表内存使用: {list_memory} 字节")
    print(f"生成器内存使用: {generator_memory} 字节")
    print(f"生成器节省内存: {list_memory / generator_memory:.0f} 倍")
    
    # 验证生成器功能
    first_10 = [next(large_generator) for _ in range(10)]
    print(f"生成器前10个值: {first_10}")


def generator_methods_demo():
    """生成器方法演示
    
    演示生成器对象的send、throw和close方法。
    send()方法可以向生成器发送值。
    throw()方法可以向生成器抛出异常。
    close()方法可以关闭生成器。
    """
    print("\n=== 生成器方法演示 ===")
    
    def echo_generator():
        """回声生成器，演示send方法"""
        while True:
            received = yield
            print(f"接收到: {received}")
    
    # 创建生成器对象
    gen = echo_generator()
    next(gen)  # 启动生成器
    
    # 发送值给生成器
    gen.send("Hello")
    gen.send("World")
    
    # 关闭生成器
    gen.close()
    print("生成器已关闭")


def best_practices():
    """迭代器与生成器最佳实践
    
    提供使用迭代器和生成器的最佳实践建议。
    """
    print("\n=== 最佳实践 ===")
    
    # 1. 优先使用生成器表达式
    print("1. 优先使用生成器表达式")
    # 好的做法
    squares = (x**2 for x in range(10))
    print(f"   生成器表达式: {type(squares)}")
    
    # 2. 使用yield from简化嵌套生成器
    print("2. 使用yield from简化嵌套生成器")
    def sub_generator():
        yield from range(3)
    
    def main_generator():
        yield from sub_generator()
        yield from range(3, 6)
    
    result = list(main_generator())
    print(f"   yield from结果: {result}")
    
    # 3. 实现__iter__方法使对象可迭代
    print("3. 实现__iter__方法使对象可迭代")
    class NumberSequence:
        def __init__(self, start, end):
            self.start = start
            self.end = end
        
        def __iter__(self):
            return iter(range(self.start, self.end))
    
    seq = NumberSequence(1, 5)
    print(f"   可迭代对象: {list(seq)}")


def main():
    """主函数 - 运行所有示例
    
    按顺序执行所有迭代器与生成器相关的示例函数，
    展示它们的概念、实现方式和优势。
    """
    print("Python迭代器与生成器学习示例\n" + "=" * 35)
    
    # 演示自定义迭代器
    print("=== 自定义倒计时迭代器 ===")
    countdown = CountDown(5)
    for num in countdown:
        print(f"倒计时: {num}")
    
    # 演示生成器
    print("\n=== 斐波那契生成器 ===")
    fib_gen = fibonacci_generator(10)
    fib_sequence = list(fib_gen)
    print(f"斐波那契数列: {fib_sequence}")
    
    # 演示无限生成器
    print("\n=== 无限计数器 ===")
    counter = infinite_counter(10, 2)
    first_5 = [next(counter) for _ in range(5)]
    print(f"前5个值: {first_5}")
    
    # 其他示例
    generator_pipeline_demo()
    memory_efficiency_demo()
    generator_methods_demo()
    best_practices()
    
    print("\n所有示例执行完成！")


if __name__ == "__main__":
    main()